/**
 * ucarinc.com Inc.
 * Copyright (c) 2014-2016 All Rights Reserved.
 */
package io.renren.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import io.renren.common.exception.RRException;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.HttpMessage;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 处理系统对外HTTP调用的工具类.
 *
 * @author haijun.zhang
 * @version 1.0
 * @title HttpUtils
 * @description 处理系统对外HTTP调用的工具类
 * @date 2016年8月29日
 */
public class HttpUtils {
    /**
     * 日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class);

    /**
     * 连接超时时间
     */
    private static final int CONNECT_TIME_OUT = 60000;

    /**
     * socket超时时间
     */
    private static final int SOCKET_TIME_OUT = 150000;

    /**
     * 错误码
     */
    private static final int ERROR_STATUS_CODE = 200;

    /**
     * 201
     */
    private static final int ERROR_STATUS_CODE_201 = 201;

    /**
     * 201
     */
    private static final int ERROR_STATUS_CODE_202 = 202;

    /**
     * UTF-8
     */
    private static final String CHARSET_UTF_8 = "UTF-8";

    /**
     * 配置
     */
    private static final RequestConfig CONFIG = RequestConfig.custom().setConnectTimeout(CONNECT_TIME_OUT).setSocketTimeout(SOCKET_TIME_OUT)
            .build();

    /**
     * 私有构造函数
     */
    private HttpUtils() {
    }

    /**
     * 发送HTTP GET请求到指定URL
     *
     * @param url     请求的URL
     * @param params  get请求的附加参数
     * @param headers header中需要添加的内容
     * @return get response内容
     */
    public static String doGet(String url, Map<String, String> params, Map<String, String> headers,UsernamePasswordCredentials usernamePasswordCredentials)
            throws RRException {



        HttpGet httpGet = null;
        InputStream inputStream = null;
        CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(CONFIG).build();
        try {
            HttpClientContext context = HttpClientContext.create();


            URI uri = new URI(url);
            httpClient = HttpClientBuilder.create().setDefaultRequestConfig(CONFIG).build();
          //  如果传入用户名密码等参数，设置Auth
            if(usernamePasswordCredentials!=null){
                CredentialsProvider provider = new BasicCredentialsProvider();

                //AuthScope scope = new AuthScope(uri.getHost(), uri.getPort(),"adinall",AuthScope.ANY_SCHEME);
                AuthScope scope = new AuthScope(uri.getHost(), uri.getPort());

                provider.setCredentials(scope, usernamePasswordCredentials);


// 创建认证缓存
             //   HttpHost targetHost = new HttpHost("admile.api.offerslook.com", 80, "http");

             //   AuthCache authCache = new BasicAuthCache();
// 创建基础认证机制 添加到缓存
            //    BasicScheme basicAuth = new BasicScheme();
           //     authCache.put(targetHost, basicAuth);

// 将认证缓存添加到执行环境中  即预填充
             //   context.setAuthCache(authCache);

                context.setCredentialsProvider(provider);
               // context.setAuthSchemeRegistry(authRegistry);
                //context.setAuthCache(authCache);
//                LOGGER.error("AuthScope.Host："+scope.getHost());
//                LOGGER.error("AuthScope.ANY_PORT："+scope.getPort());
//                LOGGER.error("AuthScope.ANY_REALM："+scope.getRealm()+"");
//                LOGGER.error("AuthScope.ANY_SCHEME："+scope.getScheme());
            }

            // url中追加参数
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (StringUtils.isNotEmpty(value)) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
                String seperator = (url.indexOf("?") == -1) ? "?" : "&";
                url += seperator + EntityUtils.toString(new UrlEncodedFormEntity(pairs, CHARSET_UTF_8));
            }
            LOGGER.info("client http doGet url:{}", url);
            httpGet = new HttpGet(url);

            // 增加header信息
            //appendHeader(httpGet, headers);
           // httpGet.addHeader("WWW-Authenticate","Basic realm=admile.api.offerslook.com");

            httpGet.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
            httpGet.addHeader("Accept-Encoding", "gzip, deflate, br");
            httpGet.addHeader("Accept-Language", "zh-CN,zh;q=0.9");
            httpGet.addHeader("Cache-Control", "no-cache");
//            httpGet.addHeader("Connection", "keep-alive");
//            httpGet.addHeader("Host", uri.getHost());
            httpGet.addHeader("Pragma", "no-cache");
            //httpGet.addHeader("Authorization", "bearer " );
//            //httpGet.addHeader("Cookie", "_ga=GA1.2.1844023576.1533654895");
//            // 发送请求
          //  String auth = "Basic " + Base64.encode(("Alexis.t@wondermars.com" + ":" + "fbb9f1307f3142df943a427a3f398bb0").getBytes());
         //   httpGet.addHeader("Authorization", auth);
            CloseableHttpResponse response = httpClient.execute(httpGet,context);

//代理认证状态
        //    AuthState proxyAuthState = context.getProxyAuthState();
          //  System.out.println("Proxy auth state: " + proxyAuthState.getState());
          //  System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
          //  System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
//目标主机认证状态
         //   AuthState targetAuthState = context.getTargetAuthState();
          //  System.out.println("Target auth state: " + targetAuthState.getState());
         //   System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
          //  System.out.println("Target auth credentials: " + targetAuthState.getCredentials());
         //   checkStatus(response, httpGet);

            // 处理response
            inputStream = response.getEntity().getContent();
            String result = IOUtils.toString(inputStream, CHARSET_UTF_8);
            LOGGER.debug("the http response is:{}", result);
            return result;
        } catch (Exception e) {
            LOGGER.error(" Client do get exception,the url is:" + url, e);
            throw new RRException(e.getMessage(), e);
        } finally {
            cleanup(inputStream, httpGet, httpClient);
        }
    }


    /**
     * Client发送HTTP GET请求到指定URL，传入的参数会以URL参数对的方式追加在url之后
     *
     * @param url    请求的URL
     * @param params 参数信息
     * @return 结果
     * @throws Exception     远程请求异常
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String doGet(String url, Map<String, String> params) throws RRException {
        return doGet(url, params, null,null);
    }

    public static String doGet(String url, Map<String, String> params, Map<String, String> headers) throws RRException {
        return doGet(url, params, headers,null);
    }

    public static String doGet(String url, Map<String, String> params,UsernamePasswordCredentials usernamePasswordCredentials) throws RRException {
        return doGet(url, params, null,usernamePasswordCredentials);
    }

    public static String doGet(String url, UsernamePasswordCredentials usernamePasswordCredentials) throws RRException {
        return doGet(url, null, null,usernamePasswordCredentials);
    }

    /**
     * Client通过HTTP POST方法发送body内容至指定URL
     *
     * @param url     目标URL
     * @param headers header中需要添加的内容
     * @return 返回结果
     * @throws Exception 远程调用异常
     */
    public static String doPost(String url, Map<String, String> params, Map<String, String> headers) throws Exception {
        InputStream inputStream = null;

        CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(CONFIG).build();

        HttpPost httpPost = new HttpPost(url);

        //appendHeader(httpPost, headers);

        try {
            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            if(params!=null){
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }

            httpPost.setEntity(new UrlEncodedFormEntity(nvps,CHARSET_UTF_8));
            httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
            httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");


            LOGGER.info("httpPost.请求参数():"+nvps.toString());

            CloseableHttpResponse response = httpClient.execute(httpPost);

            //checkStatus(response, httpPost);
            inputStream = response.getEntity().getContent();
            String result = IOUtils.toString(inputStream, Charsets.toCharset("UTF-8"));
            LOGGER.debug("the http response is:{}", result);
            return result;
        } catch (Exception e) {
            LOGGER.error("Client do post exception,the url is:" + url, e);
            throw new Exception(e.getMessage(), e);
        } finally {
            cleanup(inputStream, httpPost, httpClient);
        }
    }

    /**
     * Client通过HTTP POST方法发送body内容至指定URL
     *
     * @param url     目标URL
     * @param headers header中需要添加的内容
     * @return 返回结果
     * @throws Exception 远程调用异常
     */
    public static String doPostForm(String url, List<NameValuePair> nvps, Map<String, String> headers) throws Exception {
        InputStream inputStream = null;

        CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(CONFIG).build();

        HttpPost httpPost = new HttpPost(url);

        //appendHeader(httpPost, headers);

        try {

            httpPost.setEntity(new UrlEncodedFormEntity(nvps,CHARSET_UTF_8));
            httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
            httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");


            LOGGER.debug("httpPost.请求参数():"+nvps.toString());

            CloseableHttpResponse response = httpClient.execute(httpPost);

            //checkStatus(response, httpPost);
            inputStream = response.getEntity().getContent();
            String result = IOUtils.toString(inputStream, Charsets.toCharset("UTF-8"));
            LOGGER.debug("the http response is:{}", result);
            return result;
        } catch (Exception e) {
            LOGGER.error("Client do post exception,the url is:" + url, e);
            throw new Exception(e.getMessage(), e);
        } finally {
            cleanup(inputStream, httpPost, httpClient);
        }
    }

    /**
     * @param response    回复
     * @param httpRequest 请求
     */
    public static void checkStatus(CloseableHttpResponse response, HttpRequestBase httpRequest) throws Exception {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == ERROR_STATUS_CODE || statusCode == ERROR_STATUS_CODE_201 || statusCode == ERROR_STATUS_CODE_202) {
            LOGGER.debug("Http post success status code :" + statusCode);
        }else{
            InputStream inputStream = response.getEntity().getContent();
            String result = IOUtils.toString(inputStream, Charsets.toCharset("UTF-8"));
            LOGGER.error("the http response is:{}", result);
            httpRequest.abort();
            throw new Exception("Http post error status code :" + statusCode+"  ");
        }
    }

    /**
     * @param inputStream 输入流
     * @param request     请求
     * @param httpClient  httpclient
     */
    public static void cleanup(InputStream inputStream, HttpRequestBase request, CloseableHttpClient httpClient) {
        IOUtils.closeQuietly(inputStream);
        if (request != null) {
            request.releaseConnection();
        }
        try {
            if (httpClient != null) {
                httpClient.close();
            }
        } catch (IOException e) {
            LOGGER.error("close client exception", e);
        }
    }

    /**
     * @param headers 头信息
     * @param http http信息
     */
    public static void appendHeader(HttpMessage http, Map<String, String> headers) {
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                http.addHeader(entry.getKey(), entry.getValue());
            }
        }
    }
}
